package com.swedne.test.livedata;

import android.os.Build;
import android.os.Looper;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 *
 */
public class LiveBus {
    //分发的事件中必须要声明变量名为“EVENT”的共有常量，类型为字符串类型
    private final String EVENT_NAME = "EVENT";

    private static LiveBus instance;
    /**
     * 处理事件的集合
     */
    private Map<String, HookMutableLiveData> busMap = new HashMap<>();

    private LiveBus() {

    }

    public static LiveBus getInstance() {
        if (instance == null) {
            synchronized (LiveBus.class) {
                if (instance == null) {
                    instance = new LiveBus();
                }
            }
        }
        return instance;
    }

    public HookMutableLiveData<Object> with(String key) {
        return with(key, Object.class);
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Deprecated
    public <T> HookMutableLiveData<T> with(Class<T> type) {
        Field eventField = null;
        try {
            eventField = type.getField(EVENT_NAME);
            eventField.setAccessible(true);
            String key = (String) eventField.get(null);
            if (!busMap.containsKey(key)) {
                busMap.put(key, new HookMutableLiveData());
            }
            return busMap.get(key);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public <T> HookMutableLiveData<T> with(String key, Class<T> type) {
        if (!busMap.containsKey(key)) {
            busMap.put(key, new HookMutableLiveData());
        }
        return busMap.get(key);
    }

    public <T> void post(String key) {
        post(key, null);
    }

    public <T> void post(String key, T t) {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            with(key).setValue(t);
        } else {
            with(key).postValue(t);
        }
    }

    public static class HookMutableLiveData<T> extends MutableLiveData<T> {
        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            super.observe(owner, observer);
            try {
                hook(observer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * hook处理
         *
         * @param observer Observer<? super T>
         */
        private void hook(@NonNull Observer<? super T> observer) throws Exception {
            //获取LiveData的反射
            Class<LiveData> liveDataClass = LiveData.class;
            //获取mObservers变量（Field）
            Field mObserversField = liveDataClass.getDeclaredField("mObservers");
            //因为mObservers是私有的，所有必须加上setAccessible(true)，才可以操作
            mObserversField.setAccessible(true);
            //获取mObservers变量对应的对象
            Object observers = mObserversField.get(this);
            //获取mObservers变量对应的对象的反射，即：SafeIterableMap.class
            Class<?> observersClass = observers.getClass();
            //获取SafeIterableMap的get函数（Method）
            Method getMethod = observersClass.getDeclaredMethod("get", Object.class);
            //因为get是私有的，所有必须加上setAccessible(true)，才可以操作
            getMethod.setAccessible(true);
            //唤醒get，并调用获取Entry，注意：invoke第一个参数为要调用的对象，第二个参数为传入的参数
            Object observerWrapperEntry = getMethod.invoke(observers, observer);
            //获取Entry的Value的值
            Object observerWrapper = ((Map.Entry) observerWrapperEntry).getValue();
            //获取ObserverWrapper的反射，即：ObserverWrapper.class
            Class<?> observerWrapperClass = observerWrapper.getClass().getSuperclass();
            //获取mLastVersion（Field）
            Field lastVersionField = observerWrapperClass.getDeclaredField("mLastVersion");
            //因为mLastVersion是私有的，所有必须加上setAccessible(true)，才可以操作
            lastVersionField.setAccessible(true);
            //获取mVersion（Field）
            Field versionField = liveDataClass.getDeclaredField("mVersion");
            //因为mVersion是私有的，所有必须加上setAccessible(true)，才可以操作
            versionField.setAccessible(true);
            //获取mVersion对象
            Object version = versionField.get(this);
            //mVersion赋值mLastVersion
            lastVersionField.set(observerWrapper, version);
        }
    }

}
